package org.atlantis.evnlib;

import java.lang.reflect.Method;

import org.atlantis.evnlib.exception.EventException;
import org.atlantis.evnlib.internal.SetMap;
import org.atlantis.evnlib.internal.WeakCache;

class AnnotationReceiverFinder implements ReceiverFinder {

	private WeakCache<Object, SetMap<String, EventReceiver>> cache = new WeakCache<Object, SetMap<String, EventReceiver>>();

	@Override
	public SetMap<String, EventReceiver> scan(Object target) {
		SetMap<String, EventReceiver> receivers = cache.getCache(target);
		if (receivers != null) return receivers;
		receivers = SetMap.newInstance();
		Class<?> type = target.getClass();
		for (Method method : type.getMethods()) {
			OnEvent onEvent = inspectMethod(method);
			if (onEvent == null) continue;
			String[] eventNames = onEvent.value();
			for (String eventName : eventNames)
				receivers.put(eventName, new DefaultEventReceiver(target, method));

		}
		cache.addCache(target, receivers);
		return receivers;
	}

	private OnEvent inspectMethod(Method method) {
		OnEvent onEvent = method.getAnnotation(OnEvent.class);
		if (onEvent == null) return null;
		Class<?>[] paramTypes = method.getParameterTypes();
		if (paramTypes.length == 1 && paramTypes[0] == EventArg.class) return onEvent;
		throw new EventException("Method<%s> has @OnEvent annotation, but arguments is invalid. @OnEvent methods just "
				+ "require single EventArg argument.", method);
	}
}
